/*
 * Copyright 2011 Clean GWT
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.cleanform.gwt.chinesechess.client.activity;

import java.util.List;

import com.cleanform.gwt.bootstrap.client.ui.Button;
import com.cleanform.gwt.bootstrap.client.ui.Button.ButtonType;
import com.cleanform.gwt.bootstrap.client.ui.HeadingPanel;
import com.cleanform.gwt.bootstrap.client.ui.HeadingPanel.PanelType;
import com.cleanform.gwt.bootstrap.js.client.ui.Modal;
import com.cleanform.gwt.cell.client.ActionGroupCell.Delegate;
import com.cleanform.gwt.chinesechess.client.Chinesechess;
import com.cleanform.gwt.chinesechess.client.comet.CometClient;
import com.cleanform.gwt.chinesechess.client.comet.ServerPushEvent;
import com.cleanform.gwt.chinesechess.client.comet.ServerPushEvent.ServerPushEventHandler;
import com.cleanform.gwt.chinesechess.client.widgets.MessagePane;
import com.cleanform.gwt.chinesechess.shared.action.Actions;
import com.cleanform.gwt.chinesechess.shared.comet.UserEvent;
import com.cleanform.gwt.chinesechess.shared.comet.UserEvents;
import com.cleanform.gwt.chinesechess.shared.form.GameForm;
import com.cleanform.gwt.chinesechess.shared.form.GameHallMessageForm;
import com.cleanform.gwt.chinesechess.shared.form.NewGameForm;
import com.cleanform.gwt.chinesechess.shared.model.ChessGame;
import com.cleanform.gwt.json.client.CollectionDeserializer;
import com.cleanform.gwt.json.client.ReflectDeserializer;
import com.cleanform.gwt.reflect.client.Reflectable;
import com.cleanform.gwt.uibinder.client.RequiresActionRebind;
import com.cleanform.gwt.uibinder.client.UiHandler;
import com.cleanform.gwt.user.cellview.client.ActionGroupColumn;
import com.cleanform.gwt.user.cellview.client.DataGrid;
import com.cleanform.gwt.user.cellview.client.TextColumn;
import com.cleanform.gwt.user.client.ActionEvent;
import com.cleanform.gwt.user.client.ui.Layouts;
import com.cleanform.gwt.view.client.ReflectDataProvider;
import com.cleanform.gwt.view.client.ReflectKeyProvider;
import com.cleanform.gwt.view.client.activity.AbstractActivity;
import com.cleanform.gwt.web.client.ObjectCallback;
import com.cleanform.gwt.web.client.Requests;
import com.cleanform.gwt.web.client.StatedCallback;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Window.Location;

import static com.cleanform.gwt.user.client.ui.Layouts.as;
import static com.cleanform.gwt.user.client.ui.Layouts.hor;
import static com.cleanform.gwt.user.client.ui.Layouts.ver;
import static com.cleanform.gwt.user.client.ui.TableLayouts.td;

/**
 * The raw widget for game hall
 * 
 * @author Jess
 * @version 1.0
 * @since 1.0
 */
public abstract class GameHallView extends AbstractActivity implements RequiresActionRebind, Delegate<Reflectable> {

	public void onLoad() {
		super.onLoad();
		userPane.setCaption("Hi, " + Chinesechess.getUser());
	}

	@Override
	public void onActive(int relatedIndex) {
		// reset
		String url = Requests.buildUrl(Actions.GAME_CONTROLLER, Actions.GET_GAMES);
		Requests.postJson(url, null, new StatedCallback() {

			@Override
			protected void onSuccess(String result) {
				final List<ChessGame> response = CollectionDeserializer.get(ReflectDeserializer.get(ChessGame.class))
						.deserialize(result);
				Scheduler.get().scheduleDeferred(new Command() {

					@Override
					public void execute() {
						tableData.setList(response);
					}
				});

				cometRegistration = cometClient.addServerPushHandler(new ServerPushEventHandler() {

					@Override
					public void onServerPush(ServerPushEvent event) {
						receiveEvents(event.getComet());
					}
				});
				cometClient.startPolling((String) Chinesechess.getUser());
			}

		});
	}

	public void onInactive() {
		if (cometRegistration != null) {
			cometRegistration.removeHandler();
			cometClient.stopPolling();
		}
	}

	DataGrid tblChessGame = new DataGrid(100);
	HeadingPanel userPane = new HeadingPanel(PanelType.PRIMARY);
	Button btnLogout = new Button("Logout", ButtonType.INFO);
	Button btnNewGame = new Button("New Game");
	Button btnAutoStart = new Button("Auto Start");
	MessagePane messagePane = new MessagePane();
	ReflectDataProvider tableData = new ReflectDataProvider(new ReflectKeyProvider("gameid"));
	CometClient cometClient = CometClient.getInstance();
	HandlerRegistration cometRegistration;
	ChessGame gameToEnter;

	public GameHallView() {
		HeadingPanel gamePane = new HeadingPanel(PanelType.PRIMARY);
		gamePane.setCaption("Games");
		gamePane.setContentWidget(tblChessGame);
		gamePane.setHeight("100%");
		gamePane.getElement().getStyle().setMargin(0, Unit.PX);

		userPane.setContentWidget(Layouts.div(as(ver(btnLogout, btnNewGame, btnAutoStart)).right()));
		userPane.setHeight("200px");
		userPane.getElement().getStyle().setMargin(0, Unit.PX);

		tblChessGame.addColumn(new TextColumn("desc"), "Desc");
		tblChessGame.addColumn(new TextColumn("playerRed"), "Player Red");
		tblChessGame.addColumn(new TextColumn("playerBlack"), "Player Black");

		tblChessGame.addColumn(new ActionGroupColumn(this, "Join", "Observe"), "Join");
		tblChessGame.setSize("100%", "420px");
		tblChessGame.setColumnWidth(3, "160px");
		initWidget(hor(td(gamePane).width("100%"), as(ver(td(userPane).top(), td(messagePane).bottom())).width(260)
				.height()));
		this.setSize("100%", "560px");

		tableData.addDataDisplay(tblChessGame);

		addEventHandlers();
	}

	public GameHallMessageForm getBroadcastForm() {
		GameHallMessageForm form = GWT.create(GameHallMessageForm.class);
		form.setActor(Chinesechess.getUser());
		// form.put("actor", Chinesechess.getUser());
		return form;
	}

	public GameForm getGameForm() {
		GameForm gameForm = GWT.create(GameForm.class);
		gameForm.setActor(Chinesechess.getUser());
		// gameForm.put("actor", Chinesechess.getUser());
		return gameForm;
	}

	/**
	 * Processes on comet events callback.
	 * 
	 * @param events the comet events
	 */
	void receiveEvents(List<UserEvent> events) {
		if (events != null) {
			for (UserEvent e : events) {
				String type = e.getType();
				if (UserEvents.NEW_GAME.equals(type)) {
					tableData.getList().add(e.getGame());
				} else if (UserEvents.UPDATE_GAME.equals(type)) {
					tableData.updateListData(e.getGame());
				} else if (UserEvents.REMOVE_GAME.equals(type)) {
					tableData.remoteListData(e.getGame());
				} else if (UserEvents.GAMEHALL_MSG.equals(type)) {
					messagePane.appendMessage(e.getActor(), e.getMessage());
				}
			}
		}
	}

	@UiHandler("btnNewGame")
	void onBtnNewGameClick(ClickEvent e) {
		// gameForm = getGameForm();
		// gameForm.put("desc", "Desc");
		NewGameForm form = GWT.create(NewGameForm.class);
		form.setActor(Chinesechess.getUser());
		form.setDesc("Desc");
		String url = Requests.buildUrl(Actions.GAME_CONTROLLER, Actions.NEW_GAME);
		Requests.postObject(url, form, new ObjectCallback<ChessGame>(ChessGame.class) {

			@Override
			protected void onCallback(ChessGame response) {
				ChessGameView chessGame = getManager().getActivity(1);
				chessGame.enter(response);
				getManager().setActive(1);
			}
		});
	}

	@UiHandler("btnLogout")
	void onBtnLogoutClick(ClickEvent e) {
		String url = Requests.buildUrl(Actions.GAME_CONTROLLER, Actions.LOGOUT);
		Requests.postObject(url, Chinesechess.getUser(), new ObjectCallback<String>(String.class) {

			@Override
			protected void onCallback(String response) {
				Chinesechess.setUser(null);
				Location.assign(GWT.getHostPageBaseURL() + Location.getQueryString());
			}
		});
	}

	@UiHandler("btnAutoStart")
	void onBtnAutoStartClick(ClickEvent e) {
		Modal.message("Preserved");
	}

	@UiHandler("messagePane")
	public void onAction(ActionEvent event) {
		final String msg = messagePane.getInputMessage();
		if (msg.isEmpty()) {
			return;
		}
		GameHallMessageForm form = getBroadcastForm();
		form.setMessage(msg);
		String url = Requests.buildUrl(Actions.GAME_CONTROLLER, Actions.GAMEHALL_MSG);
		Requests.postObject(url, form, new ObjectCallback<String>(null) {

			@Override
			protected void onCallback(String response) {
				messagePane.appendMessage((String) Chinesechess.getUser(), msg);
			}
		});
	}

	@Override
	public void execute(int column, int actionIndex, Reflectable rowData) {
		ChessGame game = (ChessGame) rowData;
		if (actionIndex == 1) {
			String gameid = game.getGameid();
			GameForm gameForm = getGameForm();
			gameForm.setGameid(gameid);
			String url = Requests.buildUrl(Actions.GAME_CONTROLLER, Actions.OBSERVE_GAME);
			Requests.postObject(url, gameForm, new ObjectCallback<ChessGame>(ChessGame.class) {

				@Override
				protected void onCallback(ChessGame response) {
					ChessGameView chessGame = getManager().getActivity(1);
					chessGame.enter(response);
					getManager().setActive(1);
				}
			});

		} else if (actionIndex == 0) {
			if (game.getPlayerRed() != null && game.getPlayerBlack() != null) {
				execute(column, 1, rowData);
				return;
			}

			String gameid = game.getGameid();
			GameForm gameForm = getGameForm();
			gameForm.setGameid(gameid);
			String url = Requests.buildUrl(Actions.GAME_CONTROLLER, Actions.JOIN_GAME);
			Requests.postObject(url, gameForm, new ObjectCallback<ChessGame>(ChessGame.class) {

				@Override
				protected void onCallback(ChessGame response) {
					ChessGameView chessGame = getManager().getActivity(1);
					chessGame.enter(response);
					getManager().setActive(1);
				}
			});

		}
	}

}
